/**
 * @author Nicolas Ferrero A TabPanel with grouping support.
 */
Ext.define('Ext.ux.GroupTabPanel', {
	extend : 'Ext.Container',

	alias : 'widget.grouptabpanel',

	requires : ['Ext.tree.Panel', 'Ext.ux.GroupTabRenderer'],

	baseCls : Ext.baseCSSPrefix + 'grouptabpanel',

	initComponent : function(config) {
		var me = this;

		Ext.apply(me, config);

		// Processes items to create the TreeStore and also set up
		// "this.cards" containing the actual card items.
		me.store = me.createTreeStore();

		me.layout = {
			type : 'hbox',
			align : 'stretch'
		};
		me.defaults = {
			border : false
		};

		me.items = [{
			xtype : 'treepanel',
			cls : 'x-tree-panel x-grouptabbar',
			width : 150,
			rootVisible : false,
			store : me.store,
			hideHeaders : true,
			animate : false,
			processEvent : Ext.emptyFn,
			border : false,
			plugins : [{
						ptype : 'grouptabrenderer'
					}],
			viewConfig : {
				overItemCls : '',
				getRowClass : me.getRowClass
			},
			columns : [{
				xtype : 'treecolumn',
				sortable : false,
				dataIndex : 'text',
				flex : 1,
				renderer : function(value, cell, node, idx1, idx2, store, tree) {
					var cls = '';

					if (node.parentNode && node.parentNode.parentNode === null) {
						cls += ' x-grouptab-first';
						if (node.previousSibling) {
							cls += ' x-grouptab-prev';
						}
						if (!node.get('expanded') || node.firstChild == null) {
							cls += ' x-grouptab-last';
						}
					} else if (node.nextSibling === null) {
						cls += ' x-grouptab-last';
					} else {
						cls += ' x-grouptab-center';
					}
					if (node.data.activeTab) {
						cls += ' x-active-tab';
					}
					cell.tdCls = 'x-grouptab' + cls;

					return value;
				}
			}]
		}, {
			xtype : 'container',
			flex : 1,
			layout : 'card',
			activeItem : me.mainItem,
			baseCls : Ext.baseCSSPrefix + 'grouptabcontainer',
			items : me.cards
		}];

		me.addEvents(
				/**
				 * @event beforetabchange Fires before a tab change (activated
				 *        by {@link #setActiveTab}). Return false in any
				 *        listener to cancel the tabchange
				 * @param {Ext.ux.GroupTabPanel}
				 *            grouptabPanel The GroupTabPanel
				 * @param {Ext.Component}
				 *            newCard The card that is about to be activated
				 * @param {Ext.Component}
				 *            oldCard The card that is currently active
				 */
				'beforetabchange',

				/**
				 * @event tabchange Fires when a new tab has been activated
				 *        (activated by {@link #setActiveTab}).
				 * @param {Ext.ux.GroupTabPanel}
				 *            grouptabPanel The GroupTabPanel
				 * @param {Ext.Component}
				 *            newCard The newly activated item
				 * @param {Ext.Component}
				 *            oldCard The previously active item
				 */
				'tabchange',

				/**
				 * @event beforegroupchange Fires before a group change
				 *        (activated by {@link #setActiveGroup}). Return false
				 *        in any listener to cancel the groupchange
				 * @param {Ext.ux.GroupTabPanel}
				 *            grouptabPanel The GroupTabPanel
				 * @param {Ext.Component}
				 *            newGroup The root group card that is about to be
				 *            activated
				 * @param {Ext.Component}
				 *            oldGroup The root group card that is currently
				 *            active
				 */
				'beforegroupchange',

				/**
				 * @event groupchange Fires when a new group has been activated
				 *        (activated by {@link #setActiveGroup}).
				 * @param {Ext.ux.GroupTabPanel}
				 *            grouptabPanel The GroupTabPanel
				 * @param {Ext.Component}
				 *            newGroup The newly activated root group item
				 * @param {Ext.Component}
				 *            oldGroup The previously active root group item
				 */
				'groupchange');

		me.callParent(arguments);
		me.setActiveTab(me.activeTab);
		me.setActiveGroup(me.activeGroup);
		me.mon(me.down('treepanel').getSelectionModel(), 'select',
				me.onNodeSelect, me);
	},

	getRowClass : function(node, rowIndex, rowParams, store) {
		var cls = '';
		if (node.data.activeGroup) {
			cls += ' x-active-group';
		}
		return cls;
	},

	/**
	 * @private Node selection listener.
	 */
	onNodeSelect : function(selModel, node) {
		var me = this, currentNode = me.store.getRootNode(), parent;

		if (node.parentNode && node.parentNode.parentNode === null) {
			parent = node;
		} else {
			parent = node.parentNode;
		}

		if (me.setActiveGroup(parent.get('id')) === false
				|| me.setActiveTab(node.get('id')) === false) {
			return false;
		}

		while (currentNode) {
			currentNode.set('activeTab', false);
			currentNode.set('activeGroup', false);
			currentNode = currentNode.firstChild || currentNode.nextSibling
					|| currentNode.parentNode.nextSibling;
		}

		parent.set('activeGroup', true);
		parent.eachChild(function(child) {
					child.set('activeGroup', true);
				});
		node.set('activeTab', true);
		selModel.view.refresh();
	},

	/**
	 * Makes the given component active (makes it the visible card in the
	 * GroupTabPanel's CardLayout)
	 * 
	 * @param {Ext.Component}
	 *            cmp The component to make active
	 */
	setActiveTab : function(cmp) {
		var me = this, newTab = cmp, oldTab;

		if (Ext.isString(cmp)) {
			newTab = Ext.getCmp(newTab);
		}

		if (newTab === me.activeTab) {
			return false;
		}

		oldTab = me.activeTab;
		if (me.fireEvent('beforetabchange', me, newTab, oldTab) !== false) {
			me.activeTab = newTab;
			if (me.rendered) {
				me.down('container[baseCls=' + Ext.baseCSSPrefix
						+ 'grouptabcontainer' + ']').getLayout()
						.setActiveItem(newTab);
			}
			me.fireEvent('tabchange', me, newTab, oldTab);
		}
		return true;
	},

	/**
	 * Makes the given group active
	 * 
	 * @param {Ext.Component}
	 *            cmp The root component to make active.
	 */
	setActiveGroup : function(cmp) {
		var me = this, newGroup = cmp, oldGroup;

		if (Ext.isString(cmp)) {
			newGroup = Ext.getCmp(newGroup);
		}

		if (newGroup === me.activeGroup) {
			return true;
		}

		oldGroup = me.activeGroup;
		if (me.fireEvent('beforegroupchange', me, newGroup, oldGroup) !== false) {
			me.activeGroup = newGroup;
			me.fireEvent('groupchange', me, newGroup, oldGroup);
		} else {
			return false;
		}
		return true;
	},

	/**
	 * @private Creates the TreeStore used by the GroupTabBar.
	 */
	createTreeStore : function() {
		var me = this, groups = me.prepareItems(me.items), data = {
			text : '.',
			children : []
		}, cards = me.cards = [];
		me.activeGroup = me.activeGroup || 0;

		Ext.each(groups, function(groupItem, idx) {
			var leafItems = groupItem.items.items, rootItem = (leafItems[groupItem.mainItem] || leafItems[0]), groupRoot = {
				children : []
			};

			// Create the root node of the group
			groupRoot.id = rootItem.id;
			groupRoot.text = rootItem.title;
			groupRoot.iconCls = rootItem.iconCls;

			groupRoot.expanded = true;
			groupRoot.activeGroup = (me.activeGroup === idx);
			groupRoot.activeTab = groupRoot.activeGroup ? true : false;
			if (groupRoot.activeTab) {
				me.activeTab = groupRoot.id;
			}

			if (groupRoot.activeGroup) {
				me.mainItem = groupItem.mainItem || 0;
				me.activeGroup = groupRoot.id;
			}

			Ext.each(leafItems, function(leafItem) {
						// First node has been done
						if (leafItem.id !== groupRoot.id) {
							var child = {
								id : leafItem.id,
								leaf : true,
								text : leafItem.title,
								iconCls : leafItem.iconCls,
								activeGroup : groupRoot.activeGroup,
								activeTab : false
							};
							groupRoot.children.push(child);
						}

						// Ensure the items do not get headers
						delete leafItem.title;
						delete leafItem.iconCls;
						cards.push(leafItem);
					});

			data.children.push(groupRoot);
		});

		return Ext.create('Ext.data.TreeStore', {
					fields : ['id', 'text', 'activeGroup', 'activeTab'],
					root : {
						expanded : true
					},
					proxy : {
						type : 'memory',
						data : data
					}
				});
	},

	/**
	 * Returns the item that is currently active inside this GroupTabPanel.
	 * 
	 * @return {Ext.Component/Number} The currently active item
	 */
	getActiveTab : function() {
		return this.activeTab;
	},

	/**
	 * Returns the root group item that is currently active inside this
	 * GroupTabPanel.
	 * 
	 * @return {Ext.Component/Number} The currently active root group item
	 */
	getActiveGroup : function() {
		return this.activeGroup;
	}
});
